package com.sbx.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sbx.entity.dto.*;
import com.sbx.mapper.SessionMapper;
import com.sbx.mapper.UserMapper;
import com.sbx.service.RouteService;
import com.sbx.service.UserService;
import com.sbx.utils.AesUtil;
import com.sbx.utils.EmailUtil;
import com.sbx.utils.FormatUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private SessionMapper sessionMapper;
    @Resource
    private RouteService routeService;
    @Resource
    private AppStoreServiceImpl appStoreServiceImpl;

    @Override
    public List<User> userList() {
        return userMapper.findAll();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User insert(User user) {
        //用户名唯一

        if (null != selectUser(null, null, user.getUserName())) {
            throw new RuntimeException("用户名已存在,请重新输入!");
        }
        user.setState(StringUtils.isEmpty(user.getState()) ? 0 : user.getState());
        user.setCreated(new Date());
        userMapper.insert(user);
        return user;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteById(Integer id) {

        int i = userMapper.deleteById(id);
        if (1 > i) {
            throw new RuntimeException("无此数据，删除失败!");
        }
        return i;
    }


    @Override
    public User getUserById(String id) {
        return userMapper.selectById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(User user) {
        user.setCreated(new Date());
        return userMapper.updateById(user);

    }


    @Override
    public Page<User> getUserPage(User user, Integer pageIndex, Integer pageSize) {
        Page<User> userPage = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(!StringUtils.isEmpty(user.getUserName()), User::getUserName, user.getUserName());
        wrapper.like(!StringUtils.isEmpty(user.getNickName()), User::getNickName, user.getNickName());
        wrapper.like(!StringUtils.isEmpty(user.getEmail()), User::getEmail, user.getEmail());
        wrapper.like(!StringUtils.isEmpty(user.getCreator()), User::getCreator, user.getCreator());
        wrapper.eq(Objects.nonNull(user.getState()), User::getState, user.getState());
        return userMapper.selectPage(userPage, wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void registerByEmail(User user) {
        if (StringUtils.isEmpty(user.getNickName())) {
            user.setNickName(user.getUserName());
        }

        Assert.isTrue(FormatUtil.isMobile(user.getPhone()), "手机号不合法，请重新输入！");
        Assert.isTrue(FormatUtil.isEmail(user.getEmail()), "邮箱格式不规范，请重新输入！");
        Assert.isNull(selectUser(null, null, user.getUserName()), "用户名已存在,请重新输入!");
        Assert.isNull(selectUser(user.getEmail(), null, null), "邮箱已存在,请重新输入!");
        Assert.isNull(selectUser(null, user.getPhone(), null), "手机号已存在,请重新输入!");
        user.setState(2).setRoleId("1");
        userMapper.insert(user);
        judgeMail(user.getEmail());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String confirmEmail(String email, String code) {
        User user = selectUser(email, null, null);
        Assert.notNull(user, "用户名不存在!");
        Assert.isTrue(2 == user.getState(), "用户状态异常,不是注册状态!");
        ValueOperations<String, String> emailCodeRedis = redisTemplate.opsForValue();
        String codeInSession = emailCodeRedis.get(email);
        if (StringUtils.isEmpty(codeInSession)) {
            judgeMail(email);
        }
        Assert.isTrue(!StringUtils.isEmpty(codeInSession), "邮箱验证码已过期,请重新获取！");
        Assert.isTrue(code.equals(codeInSession), "邮箱验证码不正确,请重新输入！");
        redisTemplate.delete(email);
        user.setState(0);
        userMapper.updateById(user);
        Session session = new Session();
        String info = UUID.randomUUID().toString().replace("-", "");
        session.setUserId(user.getId()).setInfo(info);
        sessionMapper.insert(session);
        return info;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User userLogin(LoginUser loginUser, HttpServletResponse response) {
        Assert.notNull(loginUser.getUsername(), "请输入用户名!");
        Assert.notNull(loginUser.getPassword(), "请输入密码!");
        String password = AesUtil.decrypt(loginUser.getPassword());
        User user = selectUser(null, null, loginUser.getUsername());
        Assert.notNull(user, "用户名不存在!");
        Assert.isTrue(password.equals(user.getPassword()), "密码不正确，请重新输入！");
        user.setOnline(true);
        userMapper.updateById(user);
        Session session = new Session();
        String info = UUID.randomUUID().toString().replace("-", "");
        session.setUserId(user.getId()).setInfo(info);
        sessionMapper.insert(session);
        response.setHeader("token", info);
        List<Route> path = routeService.getPath(user.getRoleId());
        user.setRoutes(path);
        List<AppStore> appStores = appStoreServiceImpl.selectUserApp(user.getId());
        user.setAppStores(appStores);
        return user;

    }

    @Override
    public User tokenByUserInfo(String token) {
        Assert.notNull(token, "请输入token信息！");
        Session session = selectSession(token);
        Assert.notNull(session, "token不存在，请重新输入！");
        Assert.isTrue(!StringUtils.isEmpty(session.getUserId()) || null != userMapper.selectById(session.getId()), "用户不存在，无法提供用户信息！");
        return userMapper.selectById(session.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void userLogout(String token) {
        Assert.notNull(token, "请输入token信息！");
        Session session = selectSession(token);
        sessionMapper.deleteById(session.getId());
        LambdaQueryWrapper<Session> sessionWrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(session.getUserId())) {
            sessionWrapper.eq(Session::getUserId, session.getUserId());
            sessionMapper.delete(sessionWrapper);
        }
    }

    @Override
    public User getUserBySessionTokenId(String token) {

        Session session = sessionMapper.selectOne(new LambdaQueryWrapper<Session>().eq(Session::getInfo, token));
        if (session == null) {
            throw new IllegalArgumentException("Token:" + token + " Session 不存在");
        }
        User user = userMapper.selectById(session.getUserId());
        if (user == null) {
            throw new IllegalArgumentException("id:" + session.getUserId() + "用户不存在");
        }
        return user;
    }


    /**
     * 发送给他一个校验码。
     */
    private void judgeMail(String email) {
        //生成随机验证码
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            code.append(random.nextInt(10));
        }
        String massage = "您正在注册四不像账号，您的验证码是：" + code + "如果不是本人操作,请忽略。不要把验证码告诉任何人！";
        EmailUtil.sendMail(email, massage);

        ValueOperations<String, String> emailCodeRedis = redisTemplate.opsForValue();
        emailCodeRedis.set(email, code.toString(), 5, TimeUnit.MINUTES);
    }

    private User selectUser(String email, String phone, String userName) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(email)) {
            userLambdaQueryWrapper.eq(User::getEmail, email);
        }
        if (!StringUtils.isEmpty(phone)) {
            userLambdaQueryWrapper.eq(User::getPhone, phone);
        }
        if (!StringUtils.isEmpty(userName)) {
            userLambdaQueryWrapper.eq(User::getUserName, userName);
        }
        return userMapper.selectOne(userLambdaQueryWrapper);
    }

    private Session selectSession(String token) {
        LambdaQueryWrapper<Session> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (!StringUtils.isEmpty(token)) {
            userLambdaQueryWrapper.eq(Session::getInfo, token);
        }
        return sessionMapper.selectOne(userLambdaQueryWrapper);
    }


}
